#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>		 
#include <fcntl.h>
#include <pthread.h>
#include <termios.h>
#include <errno.h>
#include "public.h"

/*
 *	abstruct : uart operation. 
 */

static unsigned char g_thread_running = 0;
static int g_dev;

/*
 * function abstruct : uart open( 0 ~ 3 ).
 * parameter illustration: 
 *		[com]: uart number;
 */
static int serial_open(int com)
{
	int dev;
	char filename[128] ;

	if (com == 0) 	
		//sprintf(filename,"/dev/ttyAMA0") ;
		sprintf(filename,"/dev/ttyUSB0") ;
	else if (com == 1)
		sprintf(filename,"/dev/ttyAMA1") ;
	else if (com == 2)
		sprintf(filename,"/dev/ttyAMA2") ;	
	else
		sprintf(filename,"/dev/ttyAMA3") ;	

	dev = open(filename, O_RDWR|O_NOCTTY|O_NDELAY);
	if (dev < 0) {
		perror("serial open error");
		exit(1);
	}

	/* Determine whether the state of the serial port is blocking state */
	if(fcntl(dev, F_SETFL, 0) < 0) {
		printf("fcntl failed!\n");
	    return -1;
	}
	else {
	    printf("fcntl=%d\n",fcntl(dev, F_SETFL,0));
	}

	printf("serial open!\n");

	return dev;
}

/*
 * function abstruct : set serial Baud Rate.
 * parameter illustration: 
 *		[dev]: device number; [speed]: Baud rate
 */
static int set_speed(int dev, int speed)
{
	int i;
	int status;
	struct termios option;
	int speed_def[] = { B115200,B38400,B19200,B9600,B4800,B2400,B1200,B300 };
    int name_def[]  = { 115200,38400,19200,9600,4800,2400,1200,300 };

	tcgetattr(dev, &option);

	for (i = 0; i < sizeof(speed_def) / sizeof(int); i++) {
		if (speed == name_def[i]) {
			tcflush(dev, TCIOFLUSH);

			cfsetispeed(& option, speed_def[i]);
			cfsetospeed(& option, speed_def[i]);
			
			status = tcsetattr(dev, TCSANOW, & option);
			if (status != 0) {
				perror("set speed fail.");
				return -1;
			}

			tcflush(dev, TCIOFLUSH);
		}
	}

	return 0;
}

/*
 * function abstruct : set serial Parity.
 * parameter illustration: 
 *		[dev]: device number; [databit]: data bit, [stopbit]: stop bit, [parity] : parity.
 */
static int set_parity(int dev, int databit, int stopbit, int parity)
{
	struct termios options;

	if (tcgetattr(dev, & options) != 0) {
		perror("set parity error");
		return -1;
	}

	options.c_cflag &= ~CSIZE;	/* note: 容易收到的数据错位 */

	/* Set data bits */
	switch (databit) {	
		case 7:
			options.c_cflag |= CS7;
			break;
		
		case 8:
			options.c_cflag |= CS8;
			break;
		
		default:
			perror("Unsupported data size.");
			return -1;
	}

	/* Set parity bits */
	switch (parity) {
		case 'n':
		case 'N':    
			options.c_cflag &= ~PARENB;		/* Clear parity enable */
			options.c_iflag &= ~INPCK;		/* Enable parity checking */ 
			break;  

		case 'o':   
		case 'O':     
			options.c_cflag |= (PARODD | PARENB); /* Set to an odd parity */  
			options.c_iflag |= INPCK;             /* Disable parity checking */ 
			break;  

		case 'e':  
		case 'E':   
			options.c_cflag |= PARENB;		/* Enable parity */    
			options.c_cflag &= ~PARODD;		/* Convert even parity */     
			options.c_iflag |= INPCK;       /* Disable parity checking */
			break;

		case 'S': 
		case 's':  /* as no parity */   
			options.c_cflag &= ~PARENB;
			options.c_cflag &= ~CSTOPB;
			break;  

		default:   
			perror("Unsupported parity.");  
			return -1;  
	}

	/* Set stop bits */  
	switch (stopbit) {   
		case 1:    
			options.c_cflag &= ~CSTOPB;  
			break;  
		case 2:    
			options.c_cflag |= CSTOPB;  
		   break;
		default:    
			 perror("Unsupported stop bits");  
			 return -1; 
	}

	options.c_cflag |= (CLOCAL | CREAD);

	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

	options.c_oflag &= ~OPOST;
	options.c_oflag &= ~(ONLCR | OCRNL); //添加的

	options.c_iflag &= ~(ICRNL | INLCR);
	options.c_iflag &= ~(IXON | IXOFF | IXANY); //添加的

	/* Set input parity option */ 
	if (parity != 'n')   
		options.c_iflag |= INPCK; 

	tcflush(dev, TCIFLUSH);
	options.c_cc[VTIME] = 1;	/* Set timeout 15 seconds*/   
	options.c_cc[VMIN] = 1;		/* Update the options and do it NOW */
	options.c_lflag &= ~ECHO; /* 关闭回终端回显功能*/

	if (tcsetattr(dev, TCSANOW, & options) != 0) { 
		perror("set parity function fail.");   
		return -1;  
	}
	return 1;  
}

/*
 * function abstruct : data analy.
 * parameter illustration: 
 *		[len]: buffer length; [rev_buf]: string buffer.
 */
static int receive_data_analy(int len, unsigned char * rev_buf)
{
	int ret = len;
	char buffer[MAX_BUFFER] = {0};
	unsigned char package = 0;
	unsigned char * pdata;
	unsigned int index = 0;

	pdata = rev_buf;
	/* printf("receive:%s\n", pdata); */

	while (ret > 0) {
		do {
			if (package == 0) {
				if (!strncmp((const char *)pdata, "#MARKTIMEA", 10)) {
					package = 1;
					index = 0;
				}
				else {
					break;
				}
			}

			if ( index > 150 && *pdata == '\n' ) {
			//if ( index == 151 && index < len ) {
				package = 2;
			} 

			if (package == 1 ) {
				buffer[index++] = *pdata;
				//printf("%s\n", buffer);
			}			

			if (package == 2) {
				buffer[index] = '\0';
				/* printf("==============frame:%s\n", buffer); */
				//time_analysis(buffer);
				memset(buffer, 0, sizeof(buffer));
				package = 0;
			}
		} while (0);
		
		ret--;
		pdata++;
	}

	return 0;
}

/*
 * receive
 */
int uart_receive(unsigned char * buffer, int len)
{
	int byte;
	int ret;
	fd_set uart_read;
	struct timeval time;

	FD_ZERO(& uart_read);
	FD_SET(g_dev, & uart_read);
	time.tv_sec = 10;
	time.tv_usec = 0;

	ret = select(g_dev + 1, & uart_read, NULL, NULL, & time);
	if (ret) {
		byte = read(g_dev, buffer,len);
		return byte;
	}

	return 0;
}

/*
 * send
 */
int uart_send(unsigned char * buffer, int len)
{
	int byte;

	byte = write(g_dev, buffer, len);
	if (byte == len)
		return byte;
	else
		return -1;

}

/*
 * receive thread
 */
void * uart_receive_thread_none(void * param)
{
	int read_byte;
	unsigned char read_buf[MAX_BUFFER];
	int i;

	if (g_dev < 0)
		pthread_exit(NULL);

	printf("************************* pid : %d   ------> receive \n", getpid());


	g_thread_running = TRUE;
	while( g_thread_running ) {
		memset(read_buf, 0, sizeof(read_buf));

		read_byte = read(g_dev, read_buf, MAX_BUFFER);
		if (read_byte < 0) {
			printf("read from com error, read len = %d\n", read_byte);
			break;
		}
		else {
			//printf("read from com data len = %d, data list:%s\n", read_byte, read_buf); 
			//receive_data_analy(read_byte, read_buf);
			
			printf("len: %d\n", read_byte);
			for (i = 0; i < read_byte; i++) {
				printf("%02x ", read_buf[i]);

				if (i == 10)
					printf("\n");
			}
		}
	}

	printf("exit receive thread pid = %d\n", getpid());
	pthread_exit(NULL);
}

/*
 * receive thread for select
 */
void * uart_receive_thread(void * param)
{
	int read_byte;
	unsigned char read_buf[MAX_BUFFER];
	fd_set uart_read;
	struct timeval time;
	int ret = -1;
	int i=0;
	unsigned char data ;

	unsigned char cnt = 0;
	unsigned char recstatu;		// 表示是否处于一个正在接收数据包的状态
	unsigned char packerflag;	// 是否接收到一个完整的数据包标志
	int package[64] ={0};
	
	
	time.tv_sec = 10;
	time.tv_usec = 0;

	if (g_dev < 0)
		pthread_exit(NULL);

	g_thread_running = TRUE;
	while( g_thread_running ) {
		memset(read_buf, 0, sizeof(read_buf));		
		FD_ZERO(& uart_read);
		FD_SET(g_dev, & uart_read);
		ret = select(g_dev + 1, & uart_read, NULL, NULL, & time);
		if (ret) {
			read_byte = read(g_dev, &data, 1);
			printf("%02x ", data);

			if (read_byte < 0) {
				printf("read from com error, read len = %d\n", read_byte);
				break;
			}
			else {
				if (data == 0x53) {
					cnt = 0;
					recstatu = 1;
					packerflag = 0;
				}

				if (data == 0x0A) {
					if(cnt!=0){
					recstatu = 0;	
					packerflag = 1;
					package[cnt] = '\n';
					}
				}

				if (recstatu == 1)  {	
					package[cnt++] = data;							
				}

				if (packerflag == 1) {
					#ifndef OUTPUT
					printf("\n\npackage len %d\n", cnt);
					for (i = 0; i < cnt; i++) {
						printf("%02x ", package[i]);
						if (i == 10)
							printf("\n");
					}
					#endif

					memset(package, 0, 64);
					cnt = 0;
					recstatu = 0;
					packerflag = 0;
				}
			}
		}		
	}

	printf("exit receive thread pid = %d\n", getpid());
	pthread_exit(NULL);
}

/*
 * send thread
 */
void * uart_send_thread(void * param)
{
	int read_byte;
	char write_buf[MAX_BUFFER] = "xiaozhi";

	if (g_dev < 0)
		pthread_exit(NULL);

	printf("************************* pid : %d   ------> send \n", getpid());

	while( g_thread_running) {			
		printf("send com data to you... [%s]\n", write_buf) ;

		read_byte = write(g_dev,(void *)write_buf, strlen(write_buf) + 1);
		if (read_byte < 1)
		{
			printf("send com error!\n") ;

		}
			
		msleep(1000) ;
	}
	
	printf("exit send thread pid = %d\n", getpid());
	pthread_exit(NULL) ;
}

/*
 * function abstruct : uart initialization
 * parameter illustration: 
 *		[com]: uart number,[baudrate]: baud rate, [databit]: data bit
 *		[stopbit]: stop bit, [parity]: parity
 */
int uart_init(int com, int baudrate, int databit, int stopbit, char parity)
{
	int dev;

	dev = serial_open(com);
	g_dev = dev;
	printf("dev is %d\n", dev);

	set_speed(dev, baudrate);

	if (set_parity(dev, databit, stopbit, parity) == -1) {
		perror("init: set parity error");
		exit(0);
	}

	return dev;
}

void uart_exit(int dev)
{
	close(dev);
}


